package com.hutu.scoring;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hutu.config.cache.AICache;
import com.hutu.constant.AIMessageConstant;
import com.hutu.manager.AiManager;
import com.hutu.model.dto.question.QuestionAnswerDTO;
import com.hutu.model.dto.question.QuestionContentDTO;
import com.hutu.model.entity.AccountAnswer;
import com.hutu.model.entity.App;
import com.hutu.model.entity.Question;
import com.hutu.model.enums.AppTypeEnum;
import com.hutu.model.vo.QuestionVO;
import com.hutu.service.QuestionService;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * AI 打分类应用评分策略
 */
@Component
public class AiScoringStrategy extends ScoringStrategy {

    @Resource
    private QuestionService questionService;

    @Resource
    private AiManager aiManager;

    @Resource
    private RedissonClient redissonClient;

    public static final String AI_SCORING_KEY = "AI::SCORING_%s";


    @Override
    public AccountAnswer doScore(List<String> choices, App app) throws Exception {
        Long appId = app.getId();
        String jsonStr = JSONUtil.toJsonStr(choices);
        String cacheKey = AICache.getCacheKey(appId, jsonStr);
        String answerJson = AICache.aiAnswerCacheMap.getIfPresent(cacheKey);
        AccountAnswer userAnswer = transferCacheToAnswer(app, answerJson, appId, jsonStr);
        if (userAnswer != null) {
            return userAnswer;
        }
        // 添加分布式锁
        String lockKey = String.format(AI_SCORING_KEY, appId);
        RLock lock = redissonClient.getLock(lockKey);
        try {
            boolean tryLock = lock.tryLock(3, 15, TimeUnit.SECONDS);
            if (tryLock) {
                // 再次从cache获取信息 NOTE 防止很多线程都开始抢占锁,然后都在等待锁,然后都击中DB,加了一层缓存
                answerJson = AICache.aiAnswerCacheMap.getIfPresent(cacheKey);
                userAnswer = transferCacheToAnswer(app, answerJson, appId, jsonStr);
                if (userAnswer != null) {
                    return userAnswer;
                }
                // 如果cache还没有数据,则继续查询DB
                return getAccountAnswer(choices, app, appId, cacheKey, jsonStr);
            }
        } finally {
            if (lock != null && lock.isLocked()) {
                if (lock.isHeldByCurrentThread()) {
                    lock.unlock();
                }
            }
        }
        return null;
    }

    private static AccountAnswer transferCacheToAnswer(App app, String answerJson, Long appId, String jsonStr) {
        // 如果有缓存，直接返回
        if (StrUtil.isNotBlank(answerJson)) {
            // 构造返回值，填充答案对象的属性
            AccountAnswer userAnswer = JSONUtil.toBean(answerJson, AccountAnswer.class);
            userAnswer.setAppId(appId);
            userAnswer.setAppType(app.getAppType());
            userAnswer.setScoringStrategy(app.getScoringStrategy());
            userAnswer.setChoices(jsonStr);
            return userAnswer;
        }
        return null;
    }

    @NotNull
    private AccountAnswer getAccountAnswer(List<String> choices, App app, Long appId, String cacheKey, String jsonStr) {
        // 1. 根据 id 查询到题目
        Question question = questionService.getOne(
                Wrappers.lambdaQuery(Question.class).eq(Question::getAppId, appId)
        );
        QuestionVO questionVO = QuestionVO.objToVo(question);
        List<QuestionContentDTO> questionContent = questionVO.getQuestionContent();
        // 2. 调用 AI 获取结果
        // 封装 Prompt
        String userMessage = getAiTestScoringUserMessage(app, questionContent, choices);
        // AI 生成
        String result = aiManager.doSyncStableRequest(AIMessageConstant.AI_TEST_SCORING_SYSTEM_MESSAGE_SCORING, userMessage);
        // 截取需要的 JSON 信息
        int start = result.indexOf("{");
        int end = result.lastIndexOf("}");
        String json = result.substring(start, end + 1);
        // 存入缓存
        AICache.aiAnswerCacheMap.put(cacheKey, json);
        // 3. 构造返回值，填充答案对象的属性
        AccountAnswer userAnswer = JSONUtil.toBean(json, AccountAnswer.class);
        userAnswer.setAppId(appId);
        userAnswer.setAppType(app.getAppType());
        userAnswer.setScoringStrategy(app.getScoringStrategy());
        userAnswer.setChoices(jsonStr);
        return userAnswer;
    }

    @Override
    public AppTypeEnum getAppTypeEnum() {
        return AppTypeEnum.AI_SCORE;
    }

    /**
     * AI 评分用户消息封装
     *
     * @param app
     * @param questionContentDTOList
     * @param choices
     * @return
     */
    private String getAiTestScoringUserMessage(App app, List<QuestionContentDTO> questionContentDTOList, List<String> choices) {
        StringBuilder userMessage = new StringBuilder();
        userMessage.append(app.getAppName()).append("\n");
        userMessage.append(app.getAppDesc()).append("\n");
        List<QuestionAnswerDTO> questionAnswerDTOList = new ArrayList<>();
        for (int i = 0; i < questionContentDTOList.size(); i++) {
            QuestionAnswerDTO questionAnswerDTO = new QuestionAnswerDTO();
            questionAnswerDTO.setTitle(questionContentDTOList.get(i).getTitle());
            questionAnswerDTO.setUserAnswer(choices.get(i));
            questionAnswerDTOList.add(questionAnswerDTO);
        }
        userMessage.append(JSONUtil.toJsonStr(questionAnswerDTOList));
        return userMessage.toString();
    }

}
